package com.econ.powercloud.ems.service.biz;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.econ.powercloud.common.base.facade.pojo.PageResult;
import com.econ.powercloud.common.base.facade.util.JacksonUtil;
import com.econ.powercloud.ems.common.enums.*;
import com.econ.powercloud.ems.constant.SysConstant;
import com.econ.powercloud.ems.dal.entity.*;
import com.econ.powercloud.ems.domain.EmsDeviceDO;
import com.econ.powercloud.ems.pojo.*;
import com.econ.powercloud.ems.pojo.requestVO.ClusterRelationPidRequestVO;
import com.econ.powercloud.ems.pojo.requestVO.DeviceListingRequestVO;
import com.econ.powercloud.ems.pojo.requestVO.YkYtRangeRequestVO;
import com.econ.powercloud.ems.service.common.QueryCalDataCommonService;
import com.econ.powercloud.ems.service.common.QueryFlashDataCommonService;
import com.econ.powercloud.ems.service.dao.*;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.time.temporal.UnsupportedTemporalTypeException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author : wan
 * @Description :
 * @Date : 2020/11/25 15:02
 * @Modified by : wan
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DeviceService {
    private final EmsDeviceDAO emsDeviceDAO;
    private final EmsEnergyEquipmentDAO emsEnergyEquipmentDAO;
    private final IotProductYcDAO iotProductYcDAO;
    private final QueryFlashDataCommonService queryFlashDataCommonService;
    private final QueryCalDataCommonService queryCalDataCommonService;
    private final IotProductYxDAO iotProductYxDAO;
    private final EmsEnergyStationDAO emsEnergyStationDAO;
    private final IotDeviceYkYtDitDAO iotDeviceYkYtDitDAO;
    private final ExtIotNodeDAO extIotNodeDAO;
    private final ExtIotDeviceCalculationDAO extIotDeviceCalculationDAO;
    private final EmsModuleConfigDAO emsModuleConfigDAO;
    private final IotProductJhDAO iotProductJhDAO;
    private final DeviceDAO deviceDAO;
    private final IotProductModuleDAO iotProductModuleDAO;
    private final ExtIotSceneStructureDAO extIotSceneStructureDAO;
    private final ExtIotDeviceDAO extIotDeviceDAO;

    /**
     * 获取低压电池簇的列表
     *
     * @param energyStationId: 储能站id
     */
    public List<EmsDeviceVO> queryLowClusterTree(String energyStationId) {
        //查询该储能站下的所有簇
        List<EmsDevice> allClusterList = emsDeviceDAO.getListByCondition(energyStationId, null, DeviceType.CLUSTER.getCode());
        Map<String, List<EmsDevice>> emsDeviceMap = allClusterList.stream().collect(Collectors.groupingBy(d -> d.getEnergyEquipmentId()));
        //获取储能装置的名称
        List<EmsEnergyEquipment> energyEquipmentList = emsEnergyEquipmentDAO.selectByStationIds(Lists.newArrayList(energyStationId));
        List<EmsDeviceVO> resList = Lists.newArrayList();
        energyEquipmentList.stream().forEach(d -> {
            if (!CollectionUtils.isEmpty(emsDeviceMap.get(d.getEnergyEquipmentId()))) {
                //储能装置编号虚拟成设备，作为树的根节点
                EmsDeviceVO deviceVO = EmsDeviceVO.builder().deviceName(d.getEnergyEquipmentName()).build();
                List<EmsDeviceVO> list = EmsDeviceDO.entityListToVOList(emsDeviceMap.get(d.getEnergyEquipmentId()));
                deviceVO.setSubDevices(list);
                resList.add(deviceVO);
            }
        });
        return resList;
    }

    /**
     * 获取低压电池簇的列表
     * 这里暂时就是按照储能装置->相->电池簇 这三层关系去做
     *
     * @param stationId: 储能站id
     */
    public List<EmsDeviceVO> queryHighClusterTree(String stationId) {
        List<EmsDeviceVO> resList = Lists.newArrayList();
        //获取储能装置的名称
        List<EmsEnergyEquipment> equipmentList = emsEnergyEquipmentDAO.selectByStationIds(Lists.newArrayList(stationId));
        //获取所有的簇设备与相设备
        List<EmsDevice> deviceList = emsDeviceDAO.list().stream().filter(d -> !Objects.equals(d.getDeviceType(), DeviceType.BMU_MONOMER.getCode())).collect(Collectors.toList());
        for (EmsEnergyEquipment equipment : equipmentList) {
            //储能装置作为树的根节点
            EmsDeviceVO deviceVO = EmsDeviceVO.builder().deviceName(equipment.getEnergyEquipmentName()).subDevices(Lists.newArrayList()).build();
            //获取该储能装置下的相设备
            List<EmsDevice> phaseList = deviceList.stream().filter(d -> DeviceType.PHASE.getCode().equals(d.getDeviceType()) &&
                    equipment.getEnergyEquipmentId().equals(d.getEnergyEquipmentId())).collect(Collectors.toList());
            phaseList.stream().forEach(d -> {
                EmsDeviceVO phaseDevice = EmsDeviceDO.entityToVO(d);
                phaseDevice.setSubDevices(buildDeviceTree(deviceList, phaseDevice));
                deviceVO.getSubDevices().add(phaseDevice);
            });
            resList.add(deviceVO);
        }
        return resList;
    }


    /**
     * 根据设备编号获取有哪些遥测数据类型
     */
    public List<ApiDataVO> queryAnalogTypeListByDeviceCode(String deviceCode) {
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        if (emsDevice == null) {
            return Lists.newArrayList();
        }
        List<Integer> result = iotProductYcDAO.selectAnalogTypeByProductKeyAndModuleCode(emsDevice.getProductKey(), emsDevice.getModuleCode());
        if (CollectionUtils.isEmpty(result)) {
            return Lists.newArrayList();
        }
        List<ApiDataVO> list = Lists.newArrayList();
        result.stream().forEach(d -> {
            list.add(ApiDataVO.builder().code(d).name(AnalogType.getDescFromCode(d)).build());
        });
        return list;
    }

    /**
     * 根据设备编号获取有哪些遥信数据类型
     */
    public List<ApiDataVO> queryStatusTypeListByDeviceCode(String deviceCode) {
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        if (emsDevice == null) {
            return Lists.newArrayList();
        }
        List<Integer> result = iotProductYxDAO.selectStatusTypeByProductKeyAndModuleCode(emsDevice.getProductKey(), emsDevice.getModuleCode());
        if (CollectionUtils.isEmpty(result)) {
            return Lists.newArrayList();
        }
        List<ApiDataVO> list = Lists.newArrayList();
        result.stream().forEach(d -> {
            list.add(ApiDataVO.builder().code(d).name(StatusTypeCode.fromCode(d).getDesc()).build());
        });
        return list;
    }

    /**
     * 根据productKey,moduleCode,点号名称,遥测数据类型分页查找
     */
    public PageResult<List<EmsDeviceLocationVO>> queryYcListByDeviceCodeAndTypeAndRemark(String deviceCode, Integer analogType, String remark,
                                                                                         Integer pageNo, Integer pageSize) {
        List<EmsDeviceLocationVO> result = Lists.newArrayList();
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        if (emsDevice == null) {
            return PageResult.<List<EmsDeviceLocationVO>>builder().totalCount(0).pageNo(pageNo).data(result).build();
        }
        Page<IotProductYc> page = iotProductYcDAO.selectPageByCondition(emsDevice.getProductKey(), emsDevice.getModuleCode(),
                analogType, remark, pageNo, pageSize);
        if (CollectionUtils.isEmpty(page.getRecords())) {
            return PageResult.<List<EmsDeviceLocationVO>>builder().totalCount(0).pageNo(pageNo).data(result).build();
        }
        page.getRecords().stream().forEach(d -> {
            result.add(EmsDeviceLocationVO.builder()
                    .pid(emsDevice.getInitDeviceCode() + SysConstant.SPOT + d.getDit())
                    .deviceCode(emsDevice.getDeviceCode()).initDeviceCode(emsDevice.getInitDeviceCode())
                    .deviceName(emsDevice.getDeviceName())
                    .productKey(d.getProductKey()).moduleCode(d.getModuleCode()).dit(d.getDit())
                    .name(d.getName()).measureType(MeasureType.yc.getCode())
                    .unit(d.getUnit())
                    .build());
        });
        return PageResult.<List<EmsDeviceLocationVO>>builder().totalCount((int) page.getTotal()).pageNo(pageNo).data(result).build();
    }

    /**
     * 根据productKey,moduleCode,点号名称,遥测数据类型分页查找
     */
    public PageResult<List<EmsHisDataVO>> queryYxListByDeviceCodeAndTypeAndRemark(String deviceCode, Integer statusType, String remark,
                                                                                  Integer pageNo, Integer pageSize) {
        List<EmsHisDataVO> result = Lists.newArrayList();
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        if (emsDevice == null) {
            return PageResult.<List<EmsHisDataVO>>builder().totalCount(0).pageNo(pageNo).data(result).build();
        }
        Page<IotProductYx> page = iotProductYxDAO.selectPageByCondition(emsDevice.getProductKey(), emsDevice.getModuleCode(),
                statusType, remark, pageNo, pageSize);
        if (CollectionUtils.isEmpty(page.getRecords())) {
            return PageResult.<List<EmsHisDataVO>>builder().totalCount(0).pageNo(pageNo).data(result).build();
        }
        page.getRecords().stream().forEach(d -> {
            result.add(EmsHisDataVO.builder()
                    .pid(emsDevice.getInitDeviceCode() + SysConstant.SPOT + d.getDit())
                    .deviceCode(emsDevice.getDeviceCode()).initDeviceCode(emsDevice.getInitDeviceCode())
                    .deviceName(emsDevice.getDeviceName())
                    .productKey(d.getProductKey()).moduleCode(d.getModuleCode()).dit(d.getDit())
                    .name(d.getName()).measureType(MeasureType.yx.getCode())
                    .build());
        });
        return PageResult.<List<EmsHisDataVO>>builder().totalCount((int) page.getTotal()).pageNo(pageNo).data(result).build();
    }

    /**
     * 通过储能站查找对应设备树
     *
     * @param stationId: 储能站id
     * @return
     */
    public List<EmsDeviceVO> queryDeviceTree(String stationId) {
        //返回数据结果
        List<EmsDeviceVO> resList = Lists.newArrayList();
        List<EmsDevice> allDevice = emsDeviceDAO.selectByEnergyStationId(stationId);
        //获取第一层设备
        List<EmsDevice> firstDeviceList = allDevice.stream().filter(d -> d.getParentDeviceCode() == null).collect(Collectors.toList());
        firstDeviceList.stream().forEach(d -> {
            EmsDeviceVO deviceVO = EmsDeviceDO.entityToVO(d);
            deviceVO.setSubDevices(buildDeviceTree(allDevice, deviceVO));
            resList.add(deviceVO);
        });
        return resList;
    }

    /**
     * 实时数据曲线数据查询逻辑
     *
     * @param pid
     * @return
     */
    public FlashDataVO getDitValue(String pid, String initDeviceCode) {
        FlashDataVO flashDataVO = queryFlashDataCommonService.getFlashDataForDeviceCode(initDeviceCode,
                pid.replace(initDeviceCode + SysConstant.SPOT, ""), MeasureType.yc.getCode());
        return flashDataVO;
    }

    /**
     * 获取点号实时数据
     *
     * @param list
     * @return
     */
    public List<FlashDataVO> getFlashData(List<DitDataVO> list) {
        List<FlashDataVO> resultList = Lists.newArrayList();
        List<QueryDataVO> queryRunDataVOList = list.stream().filter(item -> DitTypeEnum.isFlashData(item.getDitType()))
                .map(item -> QueryDataVO.builder().pid(item.getInitDeviceCode() + SysConstant.SPOT + item.getDit())
                        .initDeviceCode(item.getInitDeviceCode()).dit(item.getDit()).build()).collect(Collectors.toList());
        List<QueryDataVO> queryCalDataVOList = list.stream().filter(item -> DitTypeEnum.isCalData(item.getDitType()))
                .map(item -> QueryDataVO.builder().pid(item.getInitDeviceCode() + SysConstant.SPOT + item.getDit())
                        .initDeviceCode(item.getInitDeviceCode()).dit(item.getDit()).build()).collect(Collectors.toList());
        resultList.addAll(queryFlashDataCommonService.getFlashData(queryRunDataVOList));
        resultList.addAll(queryCalDataCommonService.getCalData(queryCalDataVOList));
        return resultList;
    }

    /**
     * 根据条件查询设备数据
     *
     * @param stationId
     * @param equipmentId
     * @param deviceType
     * @param pageNo
     * @param pageSize
     * @return
     */
    public PageResult<List<ApiDataVO>> getPageByStationIdAndEquipmentIdAndDeviceType(String stationId, String equipmentId, Integer deviceType,
                                                                                     Integer pageNo, Integer pageSize) {
        Page<EmsDevice> page = emsDeviceDAO.getPageByStationIdAndEquipmentIdAndDeviceTypes(stationId, equipmentId,
                deviceType == null ? null : Lists.newArrayList(deviceType), pageNo, pageSize);
        List<ApiDataVO> apiDataVOS = Lists.newArrayList();
        for (EmsDevice emsDevice : page.getRecords()) {
            apiDataVOS.add(ApiDataVO.builder().code(emsDevice.getDeviceCode()).name(emsDevice.getDeviceName()).build());
        }
        return PageResult.<List<ApiDataVO>>builder().data(apiDataVOS)
                .pageNo((int) page.getCurrent()).totalCount((int) page.getTotal()).build();
    }


    public PageResult<List<ApiDataVO>> getPageChildDeviceByCondition(String deviceCode, Integer deviceType, Integer pageNo, Integer pageSize) {
        Page<EmsDevice> page = emsDeviceDAO.getPageChildDeviceByCondition(deviceCode, deviceType, pageNo, pageSize);
        List<ApiDataVO> apiDataVOS = Lists.newArrayList();
        for (EmsDevice emsDevice : page.getRecords()) {
            apiDataVOS.add(ApiDataVO.builder().code(emsDevice.getDeviceCode()).name(emsDevice.getDeviceName()).build());
        }
        return PageResult.<List<ApiDataVO>>builder().data(apiDataVOS)
                .pageNo((int) page.getCurrent()).totalCount((int) page.getTotal()).build();
    }

    /**
     * @Description: 模糊搜索设备
     * @Param: [search, energyStationId, energyEquipmentId, pageNo, pageSize]
     * @Return:
     */
    public PageResult<List<ApiDataVO>> getDeviceListBySearch(String search, String energyStationId, String energyEquipmentId, Integer pageNo, Integer pageSize) {
        Page<EmsDevice> page = emsDeviceDAO.getPageBySearch(search, energyStationId, energyEquipmentId, pageNo, pageSize);
        List<ApiDataVO> result = page.getRecords().stream()
                .map(d -> new ApiDataVO(d.getDeviceCode(), d.getDeviceName() + "(" + d.getDeviceCode() + ")")).collect(Collectors.toList());
        return PageResult.<List<ApiDataVO>>builder().data(result)
                .pageNo((int) page.getCurrent()).totalCount((int) page.getTotal()).build();
    }

    /**
     * 设置电池簇的位置信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void clusterSet(String deviceCode, String seat) {
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice, "设备不存在！");
        emsDevice.setSeat(seat);
        emsDeviceDAO.updateById(emsDevice);
    }

    @Transactional(rollbackFor = Exception.class)
    public void modifyClusterPid(ClusterRelationPidRequestVO requestVO) {
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(requestVO.getDeviceCode());
        Assert.notNull(emsDevice, "设备不存在！");
        List<EmsModuleConfig> insertPidList = requestVO.getPidInfoList().stream()
                .map(d -> EmsModuleConfig.builder().category(CategoryEnum.BATTERY_MONITOR.getCode()).module(ModulePositionEnum.CLUSTER_RELATION_PID.getCode())
                        .deviceCode(requestVO.getDeviceCode()).pid(d.getPid()).pidName(d.getPidName()).ditType(DitTypeEnum.YC.getCode())
                        .initDeviceCode(emsDevice.getInitDeviceCode())
                        .gmtCreate(System.currentTimeMillis()).gmtModify(System.currentTimeMillis()).build())
                .collect(Collectors.toList());
        emsModuleConfigDAO.deleteByDeviceCodesAndModule(Lists.newArrayList(requestVO.getDeviceCode()), ModulePositionEnum.CLUSTER_RELATION_PID.getCode());
        emsModuleConfigDAO.saveBatch(insertPidList);
    }

    public List<ContainerKindVO> getContainerInfo(String deviceCode) {
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice, "设备不存在！");
        List<EmsDevice> clusterList = emsDeviceDAO.getChildDeviceByCondition(deviceCode, DeviceType.CLUSTER.getCode());
        if (CollectionUtils.isEmpty(clusterList)) {
            return Collections.emptyList();
        }
        //对于哪些没有进行位置绑定的电池簇不返回给前端
        clusterList = clusterList.stream().filter(d -> d.getSeat() != null).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(clusterList)) {
            return Collections.emptyList();
        }
        //获取储能站，储能装置信息
        EmsEnergyStation station = emsEnergyStationDAO.selectOneByStationId(emsDevice.getEnergyStationId());
        Map<String, EmsEnergyEquipment> equipmentMap = emsEnergyEquipmentDAO.selectByStationIds(Lists.newArrayList(emsDevice.getEnergyStationId()))
                .stream().collect(Collectors.toMap(EmsEnergyEquipment::getEnergyEquipmentId, d -> d, (p1, p2) -> p1));
        List<EmsModuleConfig> moduleConfigs = emsModuleConfigDAO.selectListByModuleAndDeviceCodes(ModulePositionEnum.CONTAINER_TO_CLUSTER.getCode(), clusterList.stream().map(EmsDevice::getDeviceCode).collect(Collectors.toList()));
        Map<String, List<EmsModuleConfig>> moduleConfigMap = moduleConfigs.stream().collect(Collectors.groupingBy(d -> d.getDeviceCode(), LinkedHashMap::new, Collectors.toList()));
        //获取需要查询的实时数据
        List<QueryDataVO> queryDataVOS = Lists.newArrayList();
        clusterList.stream().forEach(device -> {
            List<EmsModuleConfig> moduleConfigList = moduleConfigMap.get(device.getDeviceCode());
            if (!CollectionUtils.isEmpty(moduleConfigList)) {
                moduleConfigList.stream().forEach(d -> {
                    queryDataVOS.add(QueryDataVO.builder().pid(d.getPid()).deviceCode(d.getDeviceCode()).initDeviceCode(device.getInitDeviceCode())
                            .dit(d.getPid().replace(device.getInitDeviceCode() + SysConstant.SPOT, "")).build());
                });
            }
        });
        List<FlashDataVO> flashDataVOS = queryFlashDataCommonService.getFlashData(queryDataVOS);
        Map<String, FlashDataVO> flashDataMap = Maps.newHashMap();
        if (!CollectionUtils.isEmpty(flashDataVOS)) {
            flashDataMap.putAll(flashDataVOS.stream().collect(Collectors.toMap(FlashDataVO::getPid, p -> p)));
        }
        //组装数据
        List<ContainerKindVO> result = Lists.newArrayList();
        clusterList.stream().forEach(device -> {
            List<EmsModuleConfig> moduleConfigList = moduleConfigMap.get(device.getDeviceCode());
            EmsModuleConfig socConfig = CollectionUtils.isEmpty(moduleConfigList) ? null : moduleConfigList.get(0);
            EmsModuleConfig tMaxConfig = (CollectionUtils.isEmpty(moduleConfigList) || moduleConfigList.size() < 2) ? null : moduleConfigList.get(1);
            //暂时认为第一个就是SOC的点号，第二个为最高温度的点号
            result.add(ContainerKindVO.builder()
                    .deviceCode(device.getDeviceCode())
                    .deviceName(device.getDeviceName())
                    .stationId(device.getEnergyStationId())
                    .stationName(station.getEnergyStationName())
                    .equipmentId(device.getEnergyEquipmentId())
                    .equipmentName(equipmentMap.get(device.getEnergyEquipmentId()).getEnergyEquipmentName())
                    .SOCFlashVO(this.getFlashVO(device, socConfig, flashDataMap))
                    .TemperFlashVO(this.getFlashVO(device, tMaxConfig, flashDataMap))
                    .seat(device.getSeat()).build());
        });
        return result;
    }

    public List<FlashVO> getClusterPidInfo(String deviceCode) {
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice, "设备不存在！");
        List<EmsModuleConfig> moduleConfigs = emsModuleConfigDAO.selectListByModuleAndDeviceCodes(ModulePositionEnum.CLUSTER_RELATION_PID.getCode(), Lists.newArrayList(deviceCode));
        if (CollectionUtils.isEmpty(moduleConfigs)) {
            return Lists.newArrayList();
        }
        //查询实时数据
        List<QueryDataVO> queryDataVOS = moduleConfigs.stream()
                .map(d -> QueryDataVO.builder().pid(d.getPid()).deviceCode(d.getDeviceCode()).initDeviceCode(emsDevice.getInitDeviceCode())
                        .dit(d.getPid().replace(emsDevice.getInitDeviceCode() + SysConstant.SPOT, "")).build())
                .collect(Collectors.toList());
        List<FlashDataVO> flashDataVOS = queryFlashDataCommonService.getFlashData(queryDataVOS);
        Map<String, FlashDataVO> flashDataMap = Maps.newHashMap();
        if (!CollectionUtils.isEmpty(flashDataVOS)) {
            flashDataMap.putAll(flashDataVOS.stream().collect(Collectors.toMap(FlashDataVO::getPid, p -> p)));
        }
        return moduleConfigs.stream().map(d -> getFlashVO(emsDevice, d, flashDataMap)).collect(Collectors.toList());
    }

    public List<ApiDataVO> getUnSeatCluster(String deviceCode) {
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice, "设备不存在！");
        List<EmsDevice> clusterList = emsDeviceDAO.getChildDeviceByCondition(deviceCode, DeviceType.CLUSTER.getCode());
        if (CollectionUtils.isEmpty(clusterList)) {
            return Collections.emptyList();
        }
        clusterList = clusterList.stream().filter(d -> d.getSeat() == null).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(clusterList)) {
            return Collections.emptyList();
        }
        return clusterList.stream().map(d -> ApiDataVO.builder().code(d.getDeviceCode()).name(d.getDeviceName()).build()).collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Exception.class)
    public void initClusterRelationPid(String stationId, String dits, String ditNames, Integer modulePosition) {
        EmsEnergyStation station = emsEnergyStationDAO.getById(stationId);
        Assert.notNull(station, "该储能站不存在!");
        List<String> ditList = JSON.parseArray(dits, String.class);
        List<String> ditNameList = JSON.parseArray(ditNames, String.class);
        List<EmsDevice> clusterList = emsDeviceDAO.getListByCondition(stationId, null, DeviceType.CLUSTER.getCode());
        if (CollectionUtils.isEmpty(clusterList)) {
            return;
        }
        List<EmsModuleConfig> insertPidList = Lists.newLinkedList();
        clusterList.stream().forEach(device -> {
            for (int i = 0; i < ditList.size(); i++) {
                insertPidList.add(EmsModuleConfig.builder().category(CategoryEnum.BATTERY_MONITOR.getCode())
                        .module(modulePosition).deviceCode(device.getDeviceCode()).ditType(DitTypeEnum.YC.getCode())
                        .pid(device.getInitDeviceCode() + SysConstant.SPOT + device.getModuleCode() + SysConstant.SPOT + ditList.get(i))
                        .pidName(ditNameList.get(i)).initDeviceCode(device.getInitDeviceCode()).gmtCreate(System.currentTimeMillis())
                        .gmtModify(System.currentTimeMillis()).build());
            }
        });
        emsModuleConfigDAO.deleteByDeviceCodesAndModule(clusterList.stream().map(EmsDevice::getDeviceCode).collect(Collectors.toList()), modulePosition);
        emsModuleConfigDAO.saveBatch(insertPidList);
    }

    /**
     * 根据设备名称获取设备信息
     */
    public PageResult<List<ApiDataVO>> getDeviceCodeByDeviceName(String name, Integer pageNo, Integer pageSize) {
        Page<EmsDevice> page = emsDeviceDAO.selectPageByDeviceName(name, pageNo, pageSize);
        List<ApiDataVO> apiDataVOS = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(page.getRecords())) {
            apiDataVOS = page.getRecords().stream()
                    .map(d -> new ApiDataVO(d.getDeviceCode(), d.getDeviceName())).collect(Collectors.toList());
        }
        return PageResult.<List<ApiDataVO>>builder().data(apiDataVOS)
                .pageNo((int) page.getCurrent()).totalCount((int) page.getTotal()).build();
    }

    /**
     * 根据条件获取设备的点号数据
     * @param deviceCode： EMS设备code
     * @param ditType: 点号类型,见DitTypeEnum枚举
     * @param typeCode: 量测类型,只有遥测遥信有对应的量测类型枚举,遥测对应AnalogType枚举,遥信对应StatusTypeCode枚举
     * @param search: 点号名称
     * @param pageNo
     * @param pageSize
     */
    public PageResult<List<DeviceDitDataVO>> getPageDeviceDit(String deviceCode, Integer ditType, Integer typeCode, String search, Integer pageNo, Integer pageSize) {
        DitTypeEnum ditTypeEnum = DitTypeEnum.fromCode(ditType);
        switch (ditTypeEnum) {
            case YC:
                return this.getDeviceYcDit(deviceCode, typeCode, search, pageNo, pageSize);
            case YX:
                return this.getDeviceYxDit(deviceCode, typeCode, search, pageNo, pageSize);
            case YT:
                return this.getDeviceYtDit(deviceCode, search, pageNo, pageSize);
            case YK:
                return this.getDeviceYkDit(deviceCode, search, pageNo, pageSize);
            case CAL_YC:
                return this.getDeviceCalYcDit(deviceCode, search, pageNo, pageSize);
            case CAL_YX:
                return this.getDeviceCalYxDit(deviceCode, search, pageNo, pageSize);
            case JH:
                return this.getDeviceJhDit(deviceCode, search, pageNo, pageSize);
            default:
                return PageResult.<List<DeviceDitDataVO>>builder().data(Collections.emptyList())
                        .pageNo(pageNo).totalCount(0).build();
        }
    }

    /**
     * 获取设备的遥测点号数据
     *
     * @param deviceCode : 设备编号
     * @param search     : 点号标识或名称
     * @param analogTypeCode: 遥测量测类型
     * @return
     */
    public PageResult<List<DeviceDitDataVO>> getDeviceYcDit(String deviceCode, Integer analogTypeCode, String search, Integer pageNo, Integer pageSize) {
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice, "设备不存在!");
        Assert.notNull(emsDevice.getProductKey(), "设备不存在遥测点号!");
        Assert.notNull(emsDevice.getModuleCode(), "设备不存在遥测点号!");
        Page<IotProductYc> page = iotProductYcDAO.selectPageBySearch(emsDevice.getProductKey(), emsDevice.getModuleCode(), analogTypeCode, search, pageNo, pageSize);
        List<DeviceDitDataVO> apiDataVOS = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(page.getRecords())) {
            apiDataVOS = page.getRecords().stream()
                    .map(d -> DeviceDitDataVO.builder()
                            .ditType(DitTypeEnum.YC.getCode()).ditTypeName(DitTypeEnum.getDescFromCode(DitTypeEnum.YC.getCode()))
                            .deviceCode(deviceCode).deviceName(emsDevice.getDeviceName())
                            .initDeviceCode(emsDevice.getInitDeviceCode()).dit(d.getDit())
                            .ditName(d.getName()).unit(d.getUnit())
                            .build()).collect(Collectors.toList());
        }
        return PageResult.<List<DeviceDitDataVO>>builder().data(apiDataVOS)
                .pageNo((int) page.getCurrent()).totalCount((int) page.getTotal()).build();
    }

    /**
     * 获取设备的遥信点号数据
     *
     * @param deviceCode : 设备编号
     * @param statusTypeCode:  遥信量测类型
     * @param search: 点号标识或名称
     * @return
     */
    public PageResult<List<DeviceDitDataVO>> getDeviceYxDit(String deviceCode, Integer statusTypeCode, String search, Integer pageNo, Integer pageSize) {
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice, "设备不存在!");
        Assert.notNull(emsDevice.getProductKey(), "设备不存在遥信点号!");
        Assert.notNull(emsDevice.getModuleCode(), "设备不存在遥信点号!");
        Page<IotProductYx> page = iotProductYxDAO.selectPageBySearch(emsDevice.getProductKey(), emsDevice.getModuleCode(), statusTypeCode, search, pageNo, pageSize);
        List<DeviceDitDataVO> apiDataVOS = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(page.getRecords())) {
            apiDataVOS = page.getRecords().stream()
                    .map(d -> DeviceDitDataVO.builder()
                            .ditType(DitTypeEnum.YX.getCode()).ditTypeName(DitTypeEnum.getDescFromCode(DitTypeEnum.YX.getCode()))
                            .deviceCode(deviceCode).deviceName(emsDevice.getDeviceName())
                            .initDeviceCode(emsDevice.getInitDeviceCode()).dit(d.getDit())
                            .ditName(d.getName())
                            .build()).collect(Collectors.toList());
        }
        return PageResult.<List<DeviceDitDataVO>>builder().data(apiDataVOS)
                .pageNo((int) page.getCurrent()).totalCount((int) page.getTotal()).build();
    }

    /**
     * 获取设备的遥调点号数据
     *
     * @param deviceCode : 设备编号
     * @param search     : 点号标识或名称
     * @return
     */
    public PageResult<List<DeviceDitDataVO>> getDeviceYtDit(String deviceCode, String search, Integer pageNo, Integer pageSize) {
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice, "设备不存在!");
        Assert.notNull(emsDevice.getProductKey(), "该设备未配置遥调点号！");
        Page<IotDeviceYkYtDit> page = iotDeviceYkYtDitDAO.selectPageBySearch(emsDevice.getInitDeviceCode(), RemoteType.YT.getCode(), search, pageNo, pageSize);
        List<DeviceDitDataVO> apiDataVOS = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(page.getRecords())) {
            apiDataVOS = page.getRecords().stream()
                    .map(d -> DeviceDitDataVO.builder()
                            .ditType(DitTypeEnum.YT.getCode()).ditTypeName(DitTypeEnum.getDescFromCode(DitTypeEnum.YT.getCode()))
                            .deviceCode(deviceCode).deviceName(emsDevice.getDeviceName())
                            .initDeviceCode(emsDevice.getInitDeviceCode()).dit(d.getDit())
                            .ditName(d.getDitName()).unit(d.getUnit())
                            .rangeEnd(d.getRangeEnd()).rangeStart(d.getRangeStart())
                            .build()).collect(Collectors.toList());
        }
        return PageResult.<List<DeviceDitDataVO>>builder().data(apiDataVOS)
                .pageNo((int) page.getCurrent()).totalCount((int) page.getTotal()).build();
    }

    /**
     * 获取设备的遥控点号数据
     *
     * @param deviceCode : 设备编号
     * @param search     : 点号标识或名称
     * @return
     */
    public PageResult<List<DeviceDitDataVO>> getDeviceYkDit(String deviceCode, String search, Integer pageNo, Integer pageSize) {
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice, "设备不存在!");
        Assert.notNull(emsDevice.getProductKey(), "该设备未配置遥控点号！");
        Page<IotDeviceYkYtDit> page = iotDeviceYkYtDitDAO.selectPageBySearch(emsDevice.getInitDeviceCode(), RemoteType.YK.getCode(), search, pageNo, pageSize);
        List<DeviceDitDataVO> apiDataVOS = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(page.getRecords())) {
            apiDataVOS = page.getRecords().stream()
                    .map(d -> DeviceDitDataVO.builder()
                            .ditType(DitTypeEnum.YK.getCode()).ditTypeName(DitTypeEnum.getDescFromCode(DitTypeEnum.YK.getCode()))
                            .deviceCode(deviceCode).deviceName(emsDevice.getDeviceName())
                            .initDeviceCode(emsDevice.getInitDeviceCode()).dit(d.getDit())
                            .ditName(d.getDitName())
                            .build()).collect(Collectors.toList());
        }
        return PageResult.<List<DeviceDitDataVO>>builder().data(apiDataVOS)
                .pageNo((int) page.getCurrent()).totalCount((int) page.getTotal()).build();
    }

    /**
     * 获取设备的计算遥测点号数据
     *
     * @param deviceCode : 设备编号
     * @param search     : 点号标识或名称
     * @return
     */
    public PageResult<List<DeviceDitDataVO>> getDeviceCalYcDit(String deviceCode, String search, Integer pageNo, Integer pageSize) {
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice, "设备不存在!");
        //设备的deviceCode就是场景中的节点id(具体可以看新增储能站的接口)
        ExtIotNode extIotNode = extIotNodeDAO.selectByNodeId(emsDevice.getDeviceCode());
        Assert.notNull(extIotNode, "设备未配置计算点号!");
        Page<ExtIotDeviceCalculation> page = extIotDeviceCalculationDAO.selectPageBySearch(extIotNode.getDevicePid(), MeasureType.yc.getCodeInIot(), search, pageNo, pageSize);
        List<DeviceDitDataVO> apiDataVOS = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(page.getRecords())) {
            apiDataVOS = page.getRecords().stream()
                    .map(d -> DeviceDitDataVO.builder()
                            .ditType(DitTypeEnum.CAL_YC.getCode()).ditTypeName(DitTypeEnum.getDescFromCode(DitTypeEnum.CAL_YC.getCode()))
                            .deviceCode(deviceCode).deviceName(emsDevice.getDeviceName())
                            .initDeviceCode(emsDevice.getInitDeviceCode()).dit(d.getComputeCode().replace(emsDevice.getInitDeviceCode() + SysConstant.SPOT, ""))
                            .ditName(d.getComputeName()).unit(d.getUnit())
                            .build()).collect(Collectors.toList());
        }
        return PageResult.<List<DeviceDitDataVO>>builder().data(apiDataVOS)
                .pageNo((int) page.getCurrent()).totalCount((int) page.getTotal()).build();
    }

    /**
     * 获取设备的计算遥信点号数据
     *
     * @param deviceCode : 设备编号
     * @param search     : 点号标识或名称
     * @return
     */
    public PageResult<List<DeviceDitDataVO>> getDeviceCalYxDit(String deviceCode, String search, Integer pageNo, Integer pageSize) {
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice, "设备不存在!");
        //设备的deviceCode就是场景中的节点id(具体可以看新增储能站的接口)
        ExtIotNode extIotNode = extIotNodeDAO.selectByNodeId(emsDevice.getDeviceCode());
        Assert.notNull(extIotNode, "设备未配置计算点号!");
        Page<ExtIotDeviceCalculation> page = extIotDeviceCalculationDAO.selectPageBySearch(extIotNode.getDevicePid(), MeasureType.yx.getCodeInIot(), search, pageNo, pageSize);
        List<DeviceDitDataVO> apiDataVOS = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(page.getRecords())) {
            apiDataVOS = page.getRecords().stream()
                    .map(d -> DeviceDitDataVO.builder()
                            .ditType(DitTypeEnum.CAL_YX.getCode()).ditTypeName(DitTypeEnum.getDescFromCode(DitTypeEnum.CAL_YX.getCode()))
                            .deviceCode(deviceCode).deviceName(emsDevice.getDeviceName())
                            .initDeviceCode(emsDevice.getInitDeviceCode()).dit(d.getComputeCode().replace(emsDevice.getInitDeviceCode() + SysConstant.SPOT, ""))
                            .ditName(d.getComputeName())
                            .build()).collect(Collectors.toList());
        }
        return PageResult.<List<DeviceDitDataVO>>builder().data(apiDataVOS)
                .pageNo((int) page.getCurrent()).totalCount((int) page.getTotal()).build();
    }

    /**
     * 获取设备的计划点号数据
     *
     * @param deviceCode : 设备编号
     * @param search     : 点号标识或名称
     * @return
     */
    public PageResult<List<DeviceDitDataVO>> getDeviceJhDit(String deviceCode, String search, Integer pageNo, Integer pageSize) {
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice, "设备不存在!");
        Assert.notNull(emsDevice.getProductKey(), "设备不存在遥信点号!");
        Assert.notNull(emsDevice.getModuleCode(), "设备不存在遥信点号!");
        Page<IotProductJh> page = iotProductJhDAO.selectPageBySearch(emsDevice.getProductKey(), emsDevice.getModuleCode(), search, pageNo, pageSize);
        List<DeviceDitDataVO> apiDataVOS = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(page.getRecords())) {
            apiDataVOS = page.getRecords().stream()
                    .map(d -> DeviceDitDataVO.builder()
                            .ditType(DitTypeEnum.JH.getCode()).ditTypeName(DitTypeEnum.getDescFromCode(DitTypeEnum.JH.getCode()))
                            .deviceCode(deviceCode).deviceName(emsDevice.getDeviceName())
                            .initDeviceCode(emsDevice.getInitDeviceCode()).dit(d.getDit())
                            .ditName(d.getName())
                            .build()).collect(Collectors.toList());
        }
        return PageResult.<List<DeviceDitDataVO>>builder().data(apiDataVOS)
                .pageNo((int) page.getCurrent()).totalCount((int) page.getTotal()).build();
    }

    public <T extends DitDataVO> List<DitDataExtraVO> getDitExtraByDitDataList(List<T> list) {
        List<DitDataExtraVO> result = Lists.newArrayList();
        List<T> ycRequestVO = list.stream().filter(d -> Objects.equals(d.getDitType(), DitTypeEnum.YC.getCode())).collect(Collectors.toList());
        List<T> yxRequestVO = list.stream().filter(d -> Objects.equals(d.getDitType(), DitTypeEnum.YX.getCode())).collect(Collectors.toList());
        List<T> calRequestVO = list.stream().filter(d -> DitTypeEnum.isCalData(d.getDitType())).collect(Collectors.toList());

        List<EmsDevice> emsDeviceList = emsDeviceDAO.selectByInitDeviceCodes(list.stream().map(d -> d.getInitDeviceCode()).collect(Collectors.toList()));
        //key:initDeviceCode + "." + moduleCode,如果moduleCode不存在，则为initDeviceCode,
        Map<String, EmsDevice> initDeviceCodeMap = emsDeviceList.stream().collect(
                Collectors.toMap(d -> d.getModuleCode() == null ? d.getInitDeviceCode() : (d.getInitDeviceCode() + SysConstant.SPOT + d.getModuleCode()), d -> d, (p1, p2) -> p1));
        if (!CollectionUtils.isEmpty(ycRequestVO)) {
            result.addAll(this.initYcDitDataInfo(ycRequestVO, initDeviceCodeMap));
        }
        if (!CollectionUtils.isEmpty(yxRequestVO)) {
            result.addAll(this.initYxDitDataInfo(yxRequestVO, initDeviceCodeMap));
        }
        if (!CollectionUtils.isEmpty(calRequestVO)) {
            result.addAll(this.initCalDitDataInfo(calRequestVO, initDeviceCodeMap));
        }
        return result;
    }

    private <T extends DitDataVO> List<DitDataExtraVO> initYcDitDataInfo(List<T> list, Map<String, EmsDevice> initDeviceCodeMap) {
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        List<DitDataExtraVO> result = Lists.newArrayList();
        Map<String, IotDevice> deviceMap = deviceDAO.selectByDeviceCodes(list.stream().map(d -> d.getInitDeviceCode()).collect(Collectors.toList()))
                .stream().collect(Collectors.toMap(IotDevice::getDeviceCode, d -> d, (p1, p2) -> p1));
        List<String> productKeys = list.stream().map(d -> deviceMap.get(d.getInitDeviceCode()).getProductKey()).collect(Collectors.toList());
        List<IotProductYc> ycList = iotProductYcDAO.selectListByProductKeysAndDits(productKeys, list.stream().map(d -> d.getDit()).collect(Collectors.toList()));
        //key:productkey + "." +dit
        Map<String, IotProductYc> ycMap = ycList.stream().collect(Collectors.toMap(d -> d.getProductKey() + SysConstant.SPOT + d.getDit(), d -> d, (p1, p2) -> p1));
        List<IotProductModule> moduleList = iotProductModuleDAO.selectByProductKeys(productKeys);
        //key: productKey + "." + moduleCode
        Map<String, IotProductModule> moduleMap = moduleList.stream().collect(Collectors.toMap(d -> d.getProductKey() + SysConstant.SPOT + d.getModuleCode(), d -> d, (p1, p2) -> p1));
        list.stream().forEach(d -> {
            IotDevice iotDevice = deviceMap.get(d.getInitDeviceCode());
            IotProductYc iotProductYc = ycMap.get(iotDevice.getProductKey() + SysConstant.SPOT + d.getDit());
            IotProductModule iotProductModule = moduleMap.get(iotDevice.getProductKey() + SysConstant.SPOT + iotProductYc.getModuleCode());
            EmsDevice emsDevice = initDeviceCodeMap.get(d.getInitDeviceCode() + SysConstant.SPOT + iotProductModule.getModuleCode());
            result.add(DitDataExtraVO.builder()
                    .initDeviceCode(d.getInitDeviceCode()).ditType(d.getDitType()).dit(d.getDit())
                    .ditName(iotProductYc == null ? null : iotProductYc.getName())
                    .unit(iotProductYc == null ? null : iotProductYc.getUnit())
                    .simpleName(iotDevice.getSimpleName()).pid(d.getInitDeviceCode() + SysConstant.SPOT + d.getDit())
                    .moduleCode(iotProductModule == null ? null : iotProductModule.getModuleCode())
                    .moduleName(iotProductModule == null ? null : iotProductModule.getModuleName())
                    .deviceCode(emsDevice == null ? null : emsDevice.getDeviceCode())
                    .deviceName(emsDevice == null ? null : emsDevice.getDeviceName())
                    .build());
        });
        return result;
    }

    private <T extends DitDataVO> List<DitDataExtraVO> initYxDitDataInfo(List<T> list, Map<String, EmsDevice> initDeviceCodeMap) {
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        List<DitDataExtraVO> result = Lists.newArrayList();
        Map<String, IotDevice> deviceMap = deviceDAO.selectByDeviceCodes(list.stream().map(d -> d.getInitDeviceCode()).collect(Collectors.toList()))
                .stream().collect(Collectors.toMap(IotDevice::getDeviceCode, d -> d, (p1, p2) -> p1));
        List<String> productKeys = list.stream().map(d -> deviceMap.get(d.getInitDeviceCode()).getProductKey()).collect(Collectors.toList());
        List<IotProductYx> yxList = iotProductYxDAO.selectListByProductKeysAndDits(productKeys, list.stream().map(d -> d.getDit()).collect(Collectors.toList()));
        //key:productkey + "." +dit
        Map<String, IotProductYx> yxMap = yxList.stream().collect(Collectors.toMap(d -> d.getProductKey() + SysConstant.SPOT + d.getDit(), d -> d, (p1, p2) -> p1));
        List<IotProductModule> moduleList = iotProductModuleDAO.selectByProductKeys(productKeys);
        //key: productKey + "." + moduleCode
        Map<String, IotProductModule> moduleMap = moduleList.stream().collect(Collectors.toMap(d -> d.getProductKey() + SysConstant.SPOT + d.getModuleCode(), d -> d, (p1, p2) -> p1));
        list.stream().forEach(d -> {
            IotDevice iotDevice = deviceMap.get(d.getInitDeviceCode());
            IotProductYx iotProductYx = yxMap.get(iotDevice.getProductKey() + SysConstant.SPOT + d.getDit());
            IotProductModule iotProductModule = moduleMap.get(iotDevice.getProductKey() + SysConstant.SPOT + iotProductYx.getModuleCode());
            EmsDevice emsDevice = initDeviceCodeMap.get(d.getInitDeviceCode() + SysConstant.SPOT + iotProductModule.getModuleCode());
            result.add(DitDataExtraVO.builder()
                    .initDeviceCode(d.getInitDeviceCode()).ditType(d.getDitType()).dit(d.getDit())
                    .ditName(iotProductYx == null ? null : iotProductYx.getName())
                    .simpleName(iotDevice.getSimpleName()).pid(d.getInitDeviceCode() + SysConstant.SPOT + d.getDit())
                    .moduleCode(iotProductModule == null ? null : iotProductModule.getModuleCode())
                    .moduleName(iotProductModule == null ? null : iotProductModule.getModuleName())
                    .deviceCode(emsDevice == null ? null : emsDevice.getDeviceCode())
                    .deviceName(emsDevice == null ? null : emsDevice.getDeviceName())
                    .build());
        });
        return result;
    }

    private <T extends DitDataVO> List<DitDataExtraVO> initCalDitDataInfo(List<T> list, Map<String, EmsDevice> initDeviceCodeMap) {
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        List<DitDataExtraVO> result = Lists.newArrayList();
        List<ExtIotDeviceCalculation> calculationList = extIotDeviceCalculationDAO.selectListByComputeCodes(
                list.stream().map(d -> d.getInitDeviceCode() + SysConstant.SPOT + d.getDit()).collect(Collectors.toList()));
        Map<String, ExtIotDeviceCalculation> calculationMap = calculationList.stream().collect(Collectors.toMap(d -> d.getComputeCode(), d -> d, (p1, p2) -> p1));
        //获取ext_iot_device中的数据
        List<ExtIotDevice> extIotDeviceList = extIotDeviceDAO.selectListByPids(calculationList.stream().map(d->d.getDevicePid()).collect(Collectors.toList()));
        Map<Integer,ExtIotDevice> extIotDeviceMap = extIotDeviceList.stream().collect(Collectors.toMap(ExtIotDevice::getPid,p->p,(p1,p2)->p1));
        list.stream().forEach(d -> {
            ExtIotDeviceCalculation calculation = calculationMap.get(d.getInitDeviceCode() + SysConstant.SPOT + d.getDit());
            ExtIotDevice extIotDevice = extIotDeviceMap.get(calculation.getDevicePid());
            EmsDevice emsDevice = initDeviceCodeMap.get(extIotDevice.getModuleCode() == null?
                    extIotDevice.getDeviceCode() : (extIotDevice.getDeviceCode() + SysConstant.SPOT + extIotDevice.getModuleCode()));
            result.add(DitDataExtraVO.builder()
                    .initDeviceCode(d.getInitDeviceCode()).ditType(d.getDitType()).dit(d.getDit())
                    .ditName(calculation == null ? null : calculation.getComputeName()).unit(calculation == null ? null : calculation.getUnit())
                    .pid(d.getInitDeviceCode() + SysConstant.SPOT + d.getDit())
                    .deviceCode(emsDevice == null ? null : emsDevice.getDeviceCode())
                    .deviceName(emsDevice == null ? null : emsDevice.getDeviceName())
                    .build());
        });
        return result;
    }


    private List<EmsDeviceVO> buildDeviceTree(List<EmsDevice> emsDevices, EmsDeviceVO parentDeviceVO) {
        List<EmsDevice> subDevices = emsDevices.stream().filter(d -> parentDeviceVO.getDeviceCode().equals(d.getParentDeviceCode())).collect(Collectors.toList());
        List<EmsDeviceVO> deviceVOS = EmsDeviceDO.entityListToVOList(subDevices);
        parentDeviceVO.setSubDevices(deviceVOS);
        if (CollectionUtils.isEmpty(deviceVOS)) {
            return null;
        }
        for (EmsDeviceVO deviceVO : deviceVOS) {
            buildDeviceTree(emsDevices, deviceVO);
        }
        return deviceVOS;
    }

    private FlashVO getFlashVO(EmsDevice emsDevice, EmsModuleConfig moduleConfig, Map<String, FlashDataVO> flashVOMap) {
        if (moduleConfig == null) {
            return FlashVO.builder().build();
        }
        FlashVO flashVO = FlashVO.builder().pid(moduleConfig.getPid()).initDeviceCode(emsDevice.getInitDeviceCode())
                .dit(moduleConfig.getPid().replace(emsDevice.getInitDeviceCode() + SysConstant.SPOT, ""))
                .ditType(moduleConfig.getDitType()).name(moduleConfig.getPidName()).build();
        //获取查询的实时数据
        FlashDataVO vo = flashVOMap.get(moduleConfig.getPid());
        if (vo != null) {
            flashVO.setTime(vo.getTime());
            flashVO.setValue(vo.getVal());
            flashVO.setUnit(vo.getUnit());
        }
        return flashVO;
    }

    public void autoClusterSetBatch() {
        List<String> phaseDeviceCodeList = emsDeviceDAO.listByType(DeviceType.PHASE.getCode()).stream().map(EmsDevice::getDeviceCode).collect(Collectors.toList());
        Assert.notEmpty(phaseDeviceCodeList, "相设备不存在");
        List<EmsDevice> updateList = Lists.newArrayList();
        phaseDeviceCodeList.forEach(d -> {
            List<EmsDevice> seatList = getSeatListByPhase(d);
            updateList.addAll(seatList);
        });
        //更新所有相的簇位置
        emsDeviceDAO.updateBatchById(updateList);
    }

    public List<EmsDevice> getSeatListByPhase(String phaseDeviceCode) {
        List<EmsDevice> clusterList = emsDeviceDAO.getListByParentId(phaseDeviceCode);
        Assert.notEmpty(clusterList, "设备不存在电池簇");
        int j = 1;
        if (clusterList.size() % 2 != 0) {
            //电池簇个数为奇数
            for (int i = 0; i < clusterList.size(); i++) {
                if (i < clusterList.size() / 2 + 1) {
                    clusterList.get(i).setSeat("1-" + (i + 1));
                } else {
                    clusterList.get(i).setSeat("2-" + j);
                    j++;
                }
            }
        } else {
            //电池簇个数为偶数
            for (int i = 0; i < clusterList.size(); i++) {
                if (i < clusterList.size() / 2) {
                    clusterList.get(i).setSeat("1-" + (i + 1));
                } else {
                    clusterList.get(i).setSeat("2-" + j);
                    j++;
                }
            }
        }
        //返回该相电池簇的位置列表
        return clusterList;
    }

    /**
     * 自动设置SOC和最大温度点号关联
     *
     * @param clusterList    簇设备列表
     * @param initDeviceCode
     */
    @Transactional(rollbackFor = Exception.class)
    public void AutoSetRelationPid(List<EmsDevice> clusterList, String initDeviceCode) {
        List<EmsModuleConfig> insertPidList = Lists.newArrayList();
        clusterList.stream().forEach(d -> {
            String moduleCode = d.getModuleCode();
            //获得该簇对应的关联点号数据
            List<RelationPidVO> pidVOList = this.getDefaultPidInfoList(moduleCode, initDeviceCode);
            //把点号数据封装
            List<EmsModuleConfig> tempPidList = pidVOList.stream()
                    .map(t -> EmsModuleConfig.builder().category(CategoryEnum.BATTERY_MONITOR.getCode())
                            .module(ModulePositionEnum.CLUSTER_RELATION_PID.getCode())
                            .deviceCode(d.getDeviceCode())
                            .pid(t.getPid())
                            .pidName(t.getPidName())
                            .ditType(DitTypeEnum.YC.getCode())
                            .initDeviceCode(initDeviceCode)
                            .gmtCreate(System.currentTimeMillis()).gmtModify(System.currentTimeMillis()).build())
                    .collect(Collectors.toList());
            //把单个设备需要更新的pid加入总的更新列表仪器更新
            insertPidList.addAll(tempPidList);
        });
        emsModuleConfigDAO.deleteByDeviceCodesAndModule(clusterList.stream().map(EmsDevice::getDeviceCode).collect(Collectors.toList()), ModulePositionEnum.CLUSTER_RELATION_PID.getCode());
        emsModuleConfigDAO.saveBatch(insertPidList);
    }

    /**
     * 默认设置SOC和最大温度
     *
     * @param moduleCode
     * @param initDeviceCode
     * @return
     */
    public List<RelationPidVO> getDefaultPidInfoList(String moduleCode, String initDeviceCode) {
        List<RelationPidVO> pidVOList = Lists.newArrayList();
        RelationPidVO SOCPidVo = new RelationPidVO();
        if (!moduleCode.equals("def")) {
            SOCPidVo.setPid(initDeviceCode + SysConstant.SPOT + moduleCode + ".SOC");
            SOCPidVo.setPidName("SOC");
            RelationPidVO TMaxPidVo = new RelationPidVO();
            TMaxPidVo.setPid(initDeviceCode + SysConstant.SPOT + moduleCode + ".Tmax");
            TMaxPidVo.setPidName("最高温度");
            pidVOList.add(SOCPidVo);
            pidVOList.add(TMaxPidVo);
        } else {
            SOCPidVo.setPid(initDeviceCode + ".SOC");
            SOCPidVo.setPidName("SOC");
            RelationPidVO TMaxPidVo = new RelationPidVO();
            TMaxPidVo.setPid(initDeviceCode + ".Tmax");
            TMaxPidVo.setPidName("最高温度");
            pidVOList.add(SOCPidVo);
            pidVOList.add(TMaxPidVo);
        }

        return pidVOList;
    }

    /**
     * 设备挂牌
     * @param requestVO
     */
    public void listing(DeviceListingRequestVO requestVO) {
        //1.获取设备及其子设备拓扑
        String deviceCode = requestVO.getDeviceCode();
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice,"设备不存在");
        String sceneCode = extIotNodeDAO.getByNodeId(deviceCode).getSceneCode();
        int listingType = requestVO.getListingType();
        //不存在组合挂牌，直接判断是否存在挂牌类型
        Assert.notNull(ListingTypeEnum.fromCode(listingType),"该挂牌类型不存在");
        List<ExtIotNode> childNodeList = this.getAllChildNodeList(deviceCode, sceneCode,listingType);
        //2.给设备挂牌
        extIotNodeDAO.updateBatchByNodeId(childNodeList);
    }

    /**
     * 获取设备及其子设备列表
     *
     * @param deviceCode
     * @param sceneCode
     * @return
     */
    private List<ExtIotNode> getAllChildNodeList(String deviceCode, String sceneCode,Integer listingType) {
        ExtIotSceneStructure root = extIotSceneStructureDAO.selectByNodeId(deviceCode);
        List<ExtIotNode> result = Lists.newArrayList();
        List<ExtIotSceneStructure> sceneStructureList = extIotSceneStructureDAO.selectListBySceneCode(sceneCode);
        Map<Integer, List<ExtIotSceneStructure>> parentIdStructureMap = sceneStructureList.stream().filter(d -> d.getParentId() != null).collect(Collectors.groupingBy(d -> d.getParentId()));
        ExtIotNode rootNode = new ExtIotNode();
        rootNode.setNodeId(deviceCode);
        rootNode.setListingType(listingType);
        result.add(rootNode);
        SceneStructureVO sceneStructureVO = JacksonUtil.convertToObj(root, SceneStructureVO.class);
        //遍历树结构并且把所有子设备添加到result列表，统一更新挂牌状态
        getStructureTree(parentIdStructureMap, sceneStructureVO,result,listingType);
        return result;
    }

    /**
     * 查找当前挂牌设备在结构图下的所有子设备（含虚拟设备和真实设备）
     * 挂牌记录在结构图关联的ext_iot_node表的listingType属性中
     *
     * @param parentIdStructureMap: key:父节点id,value:子节点信息
     * @param parentStructureVO:    父节点信息
     * @return
     */
    private void getStructureTree(Map<Integer, List<ExtIotSceneStructure>> parentIdStructureMap, SceneStructureVO parentStructureVO, List<ExtIotNode> result, Integer listingType) {
        List<ExtIotSceneStructure> extIotSceneStructures = parentIdStructureMap.get(parentStructureVO.getPid());
        if (CollectionUtils.isEmpty(extIotSceneStructures)) {
            return ;
        }
        List<SceneStructureVO> sceneStructureVOList = JacksonUtil.convertToList(extIotSceneStructures, SceneStructureVO.class).stream()
                .sorted(Comparator.comparing(SceneStructureVO::getOrderNumber)).collect(Collectors.toList());
        for (SceneStructureVO structureVO : sceneStructureVOList) {
            //添加所有子设备节点
            ExtIotNode extIotNode = new ExtIotNode();
            extIotNode.setNodeId(structureVO.getNodeId());
            extIotNode.setListingType(listingType);
            result.add(extIotNode);
            getStructureTree(parentIdStructureMap, structureVO,result,listingType);
        }
    }

    public List<ListingVO> getListingStatus(List<String> deviceCodes) {
        List<ExtIotNode> extIotNodes = extIotNodeDAO.getListingStatusByDeviceCodes(deviceCodes);
        List<ListingVO> listingVOS = new ArrayList<>();
        extIotNodes.stream().forEach(d->{
            ListingVO listingVO = JacksonUtil.convertToObj(d,ListingVO.class);
            listingVOS.add(listingVO);
        });
        return listingVOS;
    }

    public IotDeviceYkYtDit getYkYtRange(YkYtRangeRequestVO requestVO) {
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(requestVO.getDeviceCode());
        Assert.notNull(emsDevice,"设备不存在");
        return iotDeviceYkYtDitDAO.getByDeviceCodeAndDit(emsDevice.getInitDeviceCode(),requestVO.getDit());
    }
}
